desc = function(x) {
  
  A = c(mean(x, na.rm = T), median(x, na.rm = T), sd(x, na.rm = T),
        quantile(x, c(0.01, 0.05, 0.25, 0.75, 0.95, 0.99), na.rm = T))
  names(A) = c('Mean', 'Med.', 'S.D.', '1st', '5th', '25th', '75th', '95th', '99th')
  round(A, 2)
  
}

descB = function(x) {
  
  A = c(mean(x, na.rm = T), median(x, na.rm = T), min(x, na.rm = T), max(x, na.rm = T), length(x))
  names(A) = c('Mean', 'Med.', 'Min.', 'Max.', 'N.Obs.')
  c(formatC(A[1:4], digits = 2, format = 'f'), formatC(A[5], digits = 0, format = 'f'))
  
}

descsubfull = function(x, dig = 2) {
  
  A = c(mean(x, na.rm = T), sd(x, na.rm = T), 
        quantile(x, c(0.05, 0.25, 0.50, 0.75, 0.95), na.rm = T),
        length(x[!is.na(x)]))
  names(A) = c('Mean', 'S.D.', '5th', '25th', 'Med.', '75th', '95th', 'N.Obs.')
  c(formatC(A[1:7], digits = dig, format = 'f'), formatC(A[8], digits = 0, format = 'f'))
  
}

descfull = function(x, dig = 2) {
  
  A = c(mean(x, na.rm = T), median(x, na.rm = T), sd(x, na.rm = T), min(x, na.rm = T), 
        quantile(x, c(0.05, 0.25, 0.75, 0.95), na.rm = T), max(x, na.rm = T),
        length(x[!is.na(x)]))
  names(A) = c('Mean', 'Med.', 'S.D.', 'Min', '5th', '25th', '75th', '95th', 'Max', 'N.Obs.')
  c(formatC(A[1:9], digits = dig, format = 'f'), formatC(A[10], digits = 0, format = 'f'))
  
}

# define winsorization function
winsorize = function(x, lower, upper) {
  
  q_low = quantile(x, lower, na.rm = T)
  q_upp = quantile(x, upper, na.rm = T)
  x[x<q_low & !is.na(x)] = q_low
  x[x>q_upp & !is.na(x)] = q_upp
  x
  
}

# define truncation function
truncate = function(x, lower, upper) {
  
  q_low = quantile(x, lower, na.rm = T)
  q_upp = quantile(x, upper, na.rm = T)
  x[x<q_low & !is.na(x)] = NA
  x[x>q_upp & !is.na(x)] = NA
  x
  
}

# replace internal NAs if same value before and after
fillintna = function(x) {
  
  A = x
  M = sum(is.na(x))
  N = length(x)
  naind = which(is.na(x)) # has length M
  notnaind = which(!is.na(x)) # has length N-M

  if (M == N | M == 0) {
    return(A)
    
  } else if (1 %in% naind) {
    A[1:(notnaind[1]-1)] <- A[notnaind[1]]
    return(A)
    
  } else if (N %in% naind) {
#    A[notnaind[N-M]:N] <- A[notnaind[N-M]]
    return(A)
    
  } else if (identical(naind, as.integer(seq(naind[1], naind[M], 1))) & A[naind[1]-1] == A[naind[M]+1]) {
    A[naind] <- A[naind[1]-1]
    return(A)
    
  } else {
    return(A)
  }

}